import { $set } from '@feng3d/serialization';
import { Color, Mesh3D, MeshBasicMaterial3D, MeshPhongMaterial3D, Node3D, PerspectiveCamera3D, PlaneGeometry3D, Scene3D, SphereGeometry3D, WebGLRenderer3D } from 'feng3d-three';
import { TrackballControls3D } from '../../extension/controls/TrackballControls3D';
import { AsciiEffect3D } from '../../extension/effects/AsciiEffect3D';

let camera: PerspectiveCamera3D;
let controls: TrackballControls3D;
let scene: Scene3D;
let renderer: WebGLRenderer3D;
let effect: AsciiEffect3D;

let sphere: Mesh3D;
let plane: Mesh3D;

const start = Date.now();

init();
animate();

function init()
{
    camera = new Node3D().addComponent('PerspectiveCamera3D', { fov: 70, aspect: window.innerWidth / window.innerHeight, near: 1, far: 1000 });
    camera.entity.position.y = 150;
    camera.entity.position.z = 500;

    scene = new Node3D().addComponent('Scene3D');
    scene.background = new Color(0, 0, 0);

    const pointLight1 = new Node3D().addComponent('PointLight3D', { color: { value: 0xffffff } });
    pointLight1.entity.position.set(500, 500, 500);
    scene.entity.addChild(pointLight1.entity);

    const pointLight2 = new Node3D().addComponent('PointLight3D', { color: { value: 0xffffff }, intensity: 0.25 });
    pointLight2.entity.position.set(-500, -500, -500);
    scene.entity.addChild(pointLight2.entity);

    sphere = new Node3D().addComponent('Mesh3D', {
        geometry: $set(new SphereGeometry3D(), { radius: 200, widthSegments: 20, heightSegments: 10 }),
        material: $set(new MeshPhongMaterial3D(), { flatShading: true })
    });
    scene.entity.addChild(sphere.entity);

    // Plane

    plane = new Node3D().addComponent('Mesh3D', {
        geometry: $set(new PlaneGeometry3D(), { width: 400, height: 400 }),
        material: $set(new MeshBasicMaterial3D(), { color: { value: 0xe0e0e0 } })
    });
    plane.entity.position.y = -200;
    plane.entity.rotation.x = -Math.PI / 2;
    scene.entity.addChild(plane.entity);

    renderer = scene.addComponent('WebGLRenderer3D');
    renderer.setSize(window.innerWidth, window.innerHeight);

    effect = new AsciiEffect3D(renderer, ' .:-+*=%@#', { invert: true });
    effect.setSize(window.innerWidth, window.innerHeight);
    effect.domElement.style.color = 'white';
    effect.domElement.style.backgroundColor = 'black';

    // Special case: append effect.domElement, instead of renderer.domElement.
    // AsciiEffect creates a custom domElement (a div container) where the ASCII elements are placed.

    document.body.appendChild(effect.domElement);

    controls = new TrackballControls3D(camera, effect.domElement);

    //

    window.addEventListener('resize', onWindowResize);
}

function onWindowResize()
{
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
    effect.setSize(window.innerWidth, window.innerHeight);
}

//

function animate()
{
    requestAnimationFrame(animate);

    render();
}

function render()
{
    const timer = Date.now() - start;

    sphere.entity.position.y = Math.abs(Math.sin(timer * 0.002)) * 150;
    sphere.entity.rotation.x = timer * 0.0003;
    sphere.entity.rotation.z = timer * 0.0002;

    controls.update();

    effect.render(scene, camera);
}
